import type * as unifont from 'unifont';
import type { CollectedFontForMetrics } from './core/optimize-fallbacks.js';
import type {
	AstroFontProvider,
	FontFaceMetrics,
	FontFileData,
	FontType,
	GenericFallbackName,
	PreloadData,
	ResolvedFontProvider,
	Style,
} from './types.js';

export interface Hasher {
	hashString: (input: string) => string;
	hashObject: (input: Record<string, any>) => string;
}

export interface RemoteFontProviderModResolver {
	resolve: (id: string) => Promise<any>;
}

export interface RemoteFontProviderResolver {
	resolve: (provider: AstroFontProvider) => Promise<ResolvedFontProvider>;
}

export interface LocalProviderUrlResolver {
	resolve: (input: string) => string;
}

export interface ProxyData {
	weight: unifont.FontFaceData['weight'];
	style: unifont.FontFaceData['style'];
	subset: NonNullable<unifont.FontFaceData['meta']>['subset'];
}

export interface UrlProxy {
	proxy: (
		input: Pick<FontFileData, 'url' | 'init'> & {
			type: FontType;
			collectPreload: boolean;
			data: ProxyData;
		},
	) => string;
}

export interface UrlResolver {
	resolve: (hash: string) => string;
	readonly cspResources: Array<string>;
}

export interface UrlProxyContentResolver {
	resolve: (url: string) => string;
}

export interface DataCollector {
	collect: (
		input: FontFileData & {
			data: ProxyData;
			preload: PreloadData | null;
		},
	) => void;
}

export type CssProperties = Record<string, string | undefined>;

export interface CssRenderer {
	generateFontFace: (family: string, properties: CssProperties) => string;
	generateCssVariable: (key: string, values: Array<string>) => string;
}

export interface FontMetricsResolver {
	getMetrics: (name: string, font: CollectedFontForMetrics) => Promise<FontFaceMetrics>;
	generateFontFace: (input: {
		metrics: FontFaceMetrics;
		fallbackMetrics: FontFaceMetrics;
		name: string;
		font: string;
		properties: CssProperties;
	}) => string;
}

export interface SystemFallbacksProvider {
	getLocalFonts: (fallback: GenericFallbackName) => Array<string> | null;
	getMetricsForLocalFont: (family: string) => FontFaceMetrics;
}

export interface FontFetcher {
	fetch: (input: FontFileData) => Promise<Buffer>;
}

export interface FontTypeExtractor {
	extract: (url: string) => FontType;
}

export interface FontFileReader {
	extract: (input: { family: string; url: string }) => {
		weight: string;
		style: Style;
	};
}

export interface UrlProxyHashResolver {
	resolve: (input: {
		originalUrl: string;
		type: FontType;
		cssVariable: string;
		data: ProxyData;
	}) => string;
}

export interface StringMatcher {
	getClosestMatch: (target: string, candidates: Array<string>) => string;
}

export interface Storage {
	getItem: (key: string) => Promise<any | null>;
	getItemRaw: (key: string) => Promise<Buffer | null>;
	setItem: (key: string, value: any) => Promise<void>;
	setItemRaw: (key: string, value: any) => Promise<void>;
}
